package com.hzlj.position.config.rest.operator.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hzlj.position.config.common.dto.common.PositionAddDTO;
import com.hzlj.position.config.common.dto.operatorConfig.OperatorConfigQueryResultDTO;
import com.hzlj.position.config.common.enums.WarningType;
import com.hzlj.position.config.rest.LonLatAddressRest;
import com.hzlj.position.config.rest.operator.OperatorLocateRest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.function.BiFunction;

/**
 * 电信
 * L1 协议
 *
 * @author lifh
 **/
@Slf4j
@Service("telecomLocateL1V1")
public class TelecomLocateL1V1 implements OperatorLocateRest {
    @Resource
    private LonLatAddressRest lonLatAddressRest;

    @Override
    public PositionAddDTO fetchPosition(OperatorConfigQueryResultDTO config,
                                        String jgCode,
                                        String telephone,
                                        BiFunction<String, String, String> dictFun) {
        //配置请求参数
        String requestXml = config.getLocateRequestConfig().replaceAll("#telephone", telephone);
        log.debug("运营商-{}-请求参数：{}->{}", operatorName(), telephone, requestXml);
        String requestResult;
        try {
            requestResult = HttpRequest.post(config.getLocateRequestUrl())
                    .header("Content-type", "text/xml")
                    .timeout(FETCH_LOCATE_TIMEOUT)
                    .body(requestXml)
                    .charset("GBK")
                    .execute()
                    .body();
        } catch (Exception e) {
            log.error("运营商-{}-定位请求失败：{}->{}", operatorName(), telephone, requestXml, e);
            throw e;
        }


        PositionAddDTO position = defaultPosition(telephone, config);
        position.setWarningType(WarningType.FAIL.getCode());

        if (ObjectUtil.isEmpty(requestResult)) {
            log.warn("运营商-{}-请求结果：{}->{}", operatorName(), telephone, requestResult);
            return position;
        }

        try {
            JSONObject json = JSONUtil.xmlToJson(requestResult);
            log.debug("运营商-{}-请求结果：{}->{}", operatorName(), telephone, json);

            JSONObject lia = json.getJSONObject("ANS").getJSONObject("LIA");
            if (ObjectUtil.isEmpty(lia)) {
                position.setPosition(StrUtil.format("【{}】{}", "-1", "定位失败，结果解析失败"));
                return position;
            }
            String result = lia.getStr("RESULT");
            JSONObject dataJson = null;
            JSONObject posInfos = ObjectUtil.isNotEmpty(lia.get("POSINFOS")) ? lia.getJSONObject("POSINFOS") : null;
            if (posInfos != null && posInfos.containsKey("POSINFO")) {
                dataJson = posInfos.getJSONObject("POSINFO");
            }

            WarningType warningType = config.getExt().checkWarningType(result);
            if (warningType != null) {
                position.setWarningType(warningType.getCode());
            }

            //设置错误码
            position.setOperatorReturnCode(result);
            //经纬度
            String longitude = dataJson != null ? dataJson.getStr("LONGITUDE") : null;
            String latitude = dataJson != null ? dataJson.getStr("LATITUDE") : null;

            //没有位置信息,则直接返回
            if (!"0".equals(result) || ObjectUtil.hasEmpty(dataJson, latitude, longitude)) {
                String positionDesc = dictFun.apply(operatorDictType(), result);
                position.setPosition(StrUtil.format("【{}】{}", result, StrUtil.emptyToDefault(positionDesc, "未知错误")));
                return position;
            }

            position.setLongitude(formatLatOrLon(longitude));
            position.setLatitude(formatLatOrLon(latitude));
            position.setPosition(
                    lonLatAddressRest.getAddress(position.getLongitude(), position.getLatitude())
            );
            position.setWarningType(WarningType.SUCCESS.getCode());
            position.setPositionTime(DateUtil.parse(dataJson.getStr("LOCALTIME"), DatePattern.PURE_DATETIME_PATTERN));
        } catch (Exception e) {
            log.error("定位解析失败：telephone={},result={}", telephone, requestResult, e);
            position.setPosition(StrUtil.format("【{}】{}", "-1", "定位失败"));
        }
        return position;
    }


    @Override
    public String operatorName() {
        return "电信";
    }

    @Override
    public String operatorDictType() {
        return "LOCATE_TELECOM_L1_V1";
    }

    private String formatLatOrLon(String latOrLon) {
        if (StrUtil.isEmpty(latOrLon)) {
            return "";
        }
        latOrLon = latOrLon.replace("N", "").replace("E", "");
        if (NumberUtil.parseInt(latOrLon) < 181) {
            return latOrLon;
        }
        BigDecimal bigDecimal = new BigDecimal(latOrLon);
        return bigDecimal.divide(BigDecimal.valueOf(10000), 6, RoundingMode.HALF_EVEN).toString();
    }
}
